/* -*- C++ -*- */

//=============================================================================
/**
 *  @file    Auto_Ptr.h
 *
 */
//=============================================================================

#ifndef ACE_AUTO_PTR_H
#define ACE_AUTO_PTR_H
#include "common.h"

B5M_BEGIN_VERSIONED_NAMESPACE_DECL

/**
 * @class B5M_Auto_Basic_Ptr
 *
 * @brief Implements the draft C++ standard auto_ptr abstraction.
 * This class allows one to work on non-object (basic) types
 */
template <typename X>
class B5M_Auto_Basic_Ptr
{
public:
  typedef X element_type;

  // = Initialization and termination methods
  explicit B5M_Auto_Basic_Ptr (X * p = 0) : p_ (p) {}

  B5M_Auto_Basic_Ptr (B5M_Auto_Basic_Ptr<X> & rhs)
	  : p_ (rhs.release ())
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::B5M_Auto_Basic_Array_Ptr");
  }

  B5M_Auto_Basic_Ptr<X> &operator= (B5M_Auto_Basic_Ptr<X> & rhs)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Ptr<X>::B5M_Auto_Basic_Ptr");
	  if (this != &rhs)
	  {
		  this->reset (rhs.release ());
	  }
	  return *this;
  }

  ~B5M_Auto_Basic_Ptr (void)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Ptr<X>::~B5M_Auto_Basic_Ptr");
	  delete this->get ();
  }

  // = Accessor methods.
  X &operator *() const
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Ptr<X>::operator *()");
	  return *this->get ();
  }

  X *get (void) const
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Ptr<X>::get");
	  return this->p_;
  }

  X *release (void)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Ptr<X>::release");
	  X *old = this->p_;
	  this->p_ = 0;
	  return old;
  }

  void reset (X * p = 0)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Ptr<X>::reset");
	  if (this->get () != p)
		  delete this->get ();
	  this->p_ = p;
  }

protected:
  X *p_;
};

/**
 * @brief Implements the draft C++ standard auto_ptr abstraction.
 * This version can be used instead of auto_ptr<T>
 */
template <typename X>
class B5M_Auto_Ptr : public B5M_Auto_Basic_Ptr <X>
{
public:
  typedef X element_type;

  // = Initialization and termination methods
  explicit B5M_Auto_Ptr (X * p = 0) : B5M_Auto_Basic_Ptr<X> (p) {}

  X *operator-> () const
  {
	  //B5M_TRACE ("B5M_Auto_Ptr<X>::operator->");
	  return this->get ();
  }
};

/**
 * @class B5M_Auto_Basic_Array_Ptr
 *
 * @brief Implements an extension to the draft C++ standard auto_ptr
 * abstraction.  This class allows one to work on non-object
 * (basic) types that must be treated as an array, e.g.,
 * deallocated via "delete [] foo".
 */
template<typename X>
class B5M_Auto_Basic_Array_Ptr
{
public:
  typedef X element_type;

  // = Initialization and termination methods.
  explicit B5M_Auto_Basic_Array_Ptr (X * p = 0) : p_ (p) {}

  B5M_Auto_Basic_Array_Ptr (B5M_Auto_Basic_Array_Ptr<X> & R)
  : p_ (rhs.release ())
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::B5M_Auto_Basic_Array_Ptr");
  }

  B5M_Auto_Basic_Array_Ptr<X> &operator= (B5M_Auto_Basic_Array_Ptr<X> & rhs)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::operator=");
	  if (this != &rhs)
	  {
		  this->reset (rhs.release ());
	  }
	  return *this;
  }

  ~B5M_Auto_Basic_Array_Ptr (void)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::~B5M_Auto_Basic_Array_Ptr");
	  delete [] this->get ();
  }

  // = Accessor methods.
  X & operator* () const
  {
	  return *this->get ();
  }

  X & operator[] (int i) const
  {
	  X *array = this->get ();
	  return array[i];
  }

  X * get (void) const
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::get");
	  return this->p_;
  }

  X * release (void)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::release");
	  X *old = this->p_;
	  this->p_ = 0;
	  return old;
  }

  void reset (X * p = 0)
  {
	  //B5M_TRACE ("B5M_Auto_Basic_Array_Ptr<X>::reset");
	  if (this->get () != p)
		  delete [] this->get ();
	  this->p_ = p;
  }

protected:
  X * p_;
};

/**
 * @class B5M_Auto_Array_Ptr
 *
 * @brief Implements an extension to the draft C++ standard auto_ptr
 * abstraction.
 */
template<typename X>
class B5M_Auto_Array_Ptr : public B5M_Auto_Basic_Array_Ptr<X>
{
public:
  typedef X element_type;

  // = Initialization and termination methods.
  explicit B5M_Auto_Array_Ptr (X *p = 0)
    : B5M_Auto_Basic_Array_Ptr<X> (p) {}

  X *operator-> () const
  {
	  return this->get ();
  }
};


/**
 * @brief Reset given @c auto_ptr element to new element.
 *
 * Some platforms have an older version of auto_ptr support, which
 * lacks reset, and cannot be disabled easily.  Portability to these
 * platforms requires use of this function template.  This function
 * template also works for the @c B5M_Auto_{Basic_}Array_Ptr class
 * template, as well.
 */
template<typename AUTO_PTR_TYPE, typename PTR_TYPE>
inline void
B5M_auto_ptr_reset (AUTO_PTR_TYPE & ap,
                    PTR_TYPE * p)
{
  ap.reset (p);
}

B5M_END_VERSIONED_NAMESPACE_DECL

#endif